package com.butterfly.common.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

@Component
@Configuration
@Slf4j
public class RetryHttpRequestInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body,
                                        ClientHttpRequestExecution execution) throws IOException {
        int retryCount = 0;//重试一次,最多就是会调用两次
        Long start = System.currentTimeMillis();
        ClientHttpResponse response = this.retry(request, body, execution, retryCount);
        Long runingtime = System.currentTimeMillis() - start;
        try {
            HttpStatus statusCode = response.getStatusCode();
            String params = body != null ? new String(body) : "";
            String respResult = "日志未打印";
            if (response.getBody().markSupported()) {//判断响应流是否可以重复获取,避免这里获取后业务方法获取失败
                StringBuilder respSB = new StringBuilder();
                new BufferedReader(new InputStreamReader(response.getBody())).lines().forEach(s -> {
                    respSB.append(s);
                });
                respResult = respSB.toString();
            }
            //请求结果日志
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            String callerMsg = "";//获取调用方法信息
            if (stackTrace != null && stackTrace.length >= 10) {
                StackTraceElement callerStack = stackTrace[9];
                String className = "";
                if (callerStack.getClassName() != null) {
                    String[] classNamePathArr = callerStack.getClassName().split("\\.");
                    className = classNamePathArr[classNamePathArr.length - 1];
                }
                callerMsg = className + "." + callerStack.getMethodName() + ":" + callerStack.getLineNumber();
            }
            String resultLog = "[%s][CALLER:%s][DURATION:%s][URI:%s][METHOD:%s][PARAMS:%s][STATUS:%s][RESPONSE:%s]";
            Object[] resultLogParams = {"", callerMsg, runingtime, request.getURI(), request.getMethod(), params, statusCode.value(), respResult};
            if (!statusCode.is2xxSuccessful()) {//如果请求异常结果
                resultLogParams[0] = "EAMS-ACCESS-EXTERN-API-EXCEPTION";
                log.error(String.format(resultLog, resultLogParams));
            } else {
                resultLogParams[0] = "EAMS-ACCESS-EXTERN-API-NORMAL";
                log.info(String.format(resultLog, resultLogParams));
            }
            //请求时间日志
            if (runingtime < 1000) {
//                log.info("[EAMS-ACCESS-EXTERN-API-REST][REST-DURATION-LESS-ONE-SECONDS]" + durationLogSuff);
            }else if (runingtime < 3000) {
                resultLogParams[0] = "EAMS-ACCESS-EXTERN-API-REST][REST-DURATION-LESS-THREE-SECONDS";
                log.warn(String.format(resultLog, resultLogParams));
            } else {
                resultLogParams[0] = "EAMS-ACCESS-EXTERN-API-REST][REST-DURATION-GREATER-THREE-SECONDS";
                log.error(String.format(resultLog, resultLogParams));
            }
        } catch (Throwable e) {
            log.error("获取异常相应报错", e);
        }
        return response;
    }

    private ClientHttpResponse retry(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, int retryCount) throws IOException {
        try {
            ClientHttpResponse execute = execution.execute(request, body);
            return execute;
        } catch (IOException e) {
            if (retryCount-- == 0) {
                //接口调用超时日志监控标记(***FATAL关键字会发邮件报警***)
                log.error("FATAL [EAMS-ACCESS-EXTERN-API-ERROR][URI:" + request.getURI() + "]", e);
                throw new IOException("EamsRetryHttpRequestInterceptor(调用第三方接口IO异常)",e);
            }
            try {
                Thread.sleep(300L);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            return this.retry(request, body, execution, retryCount);
        }
    }
}

